package com.example.demo.util;

import java.util.Collection;
import java.util.LinkedList;
import java.util.List;
import java.util.Set;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisCallback;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.SetOperations;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.stereotype.Component;

/**
 * @author
 * @since 2019—11-19
 */
@Component
@Slf4j
public class RedisBloomFilterUtil {

    private static RedisTemplate redisTemplate;
    private static SetOperations<String, String> setOperations;
    private static ValueOperations<String, String> valueOperations;

    public static void initBit(String bitKey, int bitmapLength) {
        valueOperations.setBit(bitKey, bitmapLength, false);
    }

    @Autowired
    public void setRedisTemplate(RedisTemplate<String, String> redisTemplate) {
        RedisBloomFilterUtil.redisTemplate = redisTemplate;
        setOperations = redisTemplate.opsForSet();
        valueOperations = redisTemplate.opsForValue();
    }


    /**
     * 初始化 布隆过滤器
     *
     * @param indexs 要初始化的bit位集合
     * @param key rediskey值
     * @param size 每次操作多少
     */
    public static void setAllBit(Set<Long> indexs, String key, int size) {

        List<Long> indexList = new LinkedList();
        for (Long index : indexs) {
            indexList.add(index);
            if (indexList.size() == size) {
                addBitPip(indexList, key);
                indexList.clear();
            }
        }
        addBitPip(indexList, key);
        indexList.clear();

    }

    //添加元素
    public static void addBitPip(List<Long> list, String keys) {

        List<Object> objects = redisTemplate.executePipelined((RedisCallback<Long>) connection -> {
            for (Long index : list) {
                connection.setBit(keys.getBytes(), index, true);
            }
            return null;
        });
    }

    //判断元素是否存在
    public static boolean bitMembers(Long[] list, byte[] key) {

        List<Boolean> pipelined = redisTemplate.executePipelined((RedisCallback<Boolean>) connection -> {
            for (Long index : list) {
                connection.getBit(key, index);

            }
            return null;
        });
        return !pipelined.contains(false);

//        for (Long index : list) {
//            Boolean flag =valueOperations.getBit(key , index);
//            if (Boolean.FALSE.equals(flag))
//                return false;
//        }
//        return true;

    }


    /**
     * 批量添加数据到 set 缓存
     */
    public static void setOperationsAdd(String key, Collection<String> collection) {
        if (collection.size() <= 0) {
            return;
        }
        byte[] keyBytes = key.getBytes();
        if (collection.size() > 3000) {
            List<String> list = new LinkedList<>();
            for (String s : collection) {
                list.add(s);
                if (list.size() >= 3000) {
                    redisTemplate.execute((RedisCallback<Long>) redisConnection -> redisConnection.sAdd(keyBytes, getBytes(list)));
                    list.clear();
                }
            }
            redisTemplate.execute((RedisCallback<Long>) redisConnection -> redisConnection.sAdd(keyBytes, getBytes(list)));
        } else {
            redisTemplate.execute((RedisCallback<Long>) redisConnection -> redisConnection.sAdd(keyBytes, getBytes(collection)));
        }

    }

    public static byte[][] getBytes(Collection<String> list) {
        byte[][] values = new byte[list.size()][];
        int i = 0;
        for (String s : list) {
            values[i++] = s.getBytes();
        }
        return values;
    }

    /**
     * 判断set缓存是否存在field
     */
    public static Boolean setOperationsIsMember(String key, String field) {
        Boolean flag = setOperations.isMember(key, field);
        return flag;
    }

}

class RedisBitBoolean {

    private boolean bitIsMembers = true;

    protected void setMembers(Boolean flag) {
        if (flag instanceof Boolean && bitIsMembers && !flag) {
            bitIsMembers = flag;
        }
    }

    protected boolean isBitIsMembers() {
        return bitIsMembers;
    }

}
